#include <QInputDialog>
#include <QMessageBox>
#include "Const.h"
#include "LogonWindow.h"
#include "MainWindow.h"
#include "RegWindow.h"
#include "ui_MainWindow.h"

/**
 * 构造方法。
 * @param parent    父窗口
 */
MainWindow::MainWindow(QWidget* parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow) {
    ui->setupUi(this);

    // 设置状态栏
    int labelWidth = QMainWindow::width() / Const::STATUS_BAR_PART_COUNT;
    ui->statusBar->addWidget(&mLabelStatus, labelWidth);
    ui->statusBar->addWidget(&mLabelFriendCount, labelWidth);
    mLabelStatus.setText(tr("IDS_STATUS_LOGOFF"));
    mLabelFriendCount.setText(tr("IDS_FRIEND_COUNT").arg(0));

    // 创建客户端
    try {
        mClient = new Client();
    } catch (int) {
        QString message;
        this->getResultMessage(ResultCode::NETWORK_ERROR, &message);
        QMessageBox::critical(this, " ", message);
        exit(0);
    }

    // 连接信号与槽
    QMainWindow::connect(mClient, SIGNAL(UM_CHAT_S2C(ChatInfo*)), SLOT(onChatS2C(ChatInfo*)));
    QMainWindow::connect(mClient, SIGNAL(UM_FRIEND_LOGOFF(LogoffRequest*)), SLOT(onFriendLogoff(LogoffRequest*)));
    QMainWindow::connect(mClient, SIGNAL(UM_FRIEND_LOGON(FriendLogon*)), SLOT(onFriendLogon(FriendLogon*)));
    QMainWindow::connect(mClient, SIGNAL(UM_GET_ADD_FRIEND_REQUEST(AddFriendRequest*)), SLOT(onGetAddFriendRequest(AddFriendRequest*)));
    QMainWindow::connect(mClient, SIGNAL(UM_GET_ADD_FRIEND_RESULT(AddFriendResult*)), SLOT(onGetAddFriendResult(AddFriendResult*)));
    QMainWindow::connect(mClient, SIGNAL(UM_GET_LOGON_RESULT(LogonResult*)), SLOT(onGetLogonResult(LogonResult*)));
    QMainWindow::connect(mClient, SIGNAL(UM_GET_REG_RESULT(RegResult*)), SLOT(onGetRegResult(RegResult*)));
}

/**
 * 析构方法。
 */
MainWindow::~MainWindow() {
    // 清除所有聊天窗口
    this->clearChatWindow();

    // 清空好友列表控件
    ui->listViewUsers->clear();

    // 删除客户端
    if (mClient != nullptr) {
        delete mClient;
    }

    delete ui;
}

/**
 * 添加所有好友到好友列表控件中。
 * @param result    登录结果
 */
void MainWindow::addAllFriends(LogonResult* result) {
    for (int i = 0; i < result->mFriendCount; i++) {
        this->addOneFriend(result->mFriends[i].mUsername, result->mFriends[i].mIconIndex, result->mFriendsOnline[i]);
    }

    mLabelFriendCount.setText(tr("IDS_FRIEND_COUNT").arg(QString::number(result->mFriendCount)));
}

/**
 * 添加一个好友到好友列表控件中。
 * @param friendName    好友名
 * @param iconIndex     好友头像索引
 * @param isOnline      好友在线则为 true，否则为 false
 */
void MainWindow::addOneFriend(const char* friendName, int iconIndex, bool isOnline) {
    if (iconIndex < 0) {
        return;
    }
    ui->listViewUsers->addItem(friendName, iconIndex, isOnline);
}

/**
 * 改变界面状态。
 * @param isLogon   已登录则为 true，否则为 false
 */
void MainWindow::changeState(bool isLogon) {
    ui->buttonLogon->setEnabled(!isLogon);
    ui->buttonReg->setEnabled(!isLogon);
    ui->buttonAddFriend->setEnabled(isLogon);
    ui->buttonMChat->setEnabled(isLogon);
    ui->buttonLogoff->setEnabled(isLogon);

    QString text;
    if (isLogon) {
        text = tr("IDS_STATUS_LOGON");
        mLabelStatus.setText(text);
    } else {
        text = tr("IDS_STATUS_LOGOFF");
        mLabelStatus.setText(text);
    }
    text = tr("IDS_FRIEND_COUNT").arg(0);
    mLabelFriendCount.setText(text);
}

/**
 * 清除所有聊天窗口。
 */
void MainWindow::clearChatWindow() {
    Chats::iterator end = mChats.end();
    for (Chats::iterator i = mChats.begin(); i != end; i++) {
        delete i.value();
    }
    mChats.clear();
}

/**
 * 获取指定好友名对应的聊天窗口。
 * @param friendName    好友名
 * @return 好友名对应的聊天窗口
 */
ChatWindow* MainWindow::getChatWindow(const char* friendName) {
    // 查找用户名对应的聊天窗口
    ChatWindow* window = nullptr;
    Chats::iterator it = mChats.find(friendName);

    if (it == mChats.end()) {
        // 未找到，则新建一个
        window = new ChatWindow(friendName, this);
        QMainWindow::connect(window, SIGNAL(UM_CHAT_C2S(ChatInfo*)), SLOT(onChatC2S(ChatInfo*)));
        mChats.insert(friendName, window);
    } else {
        window = it.value();
    }

    return window;
}

/**
 * 获取结果信息。
 * @param resultCode    结果码
 * @param text          返回的结果信息
 */
void MainWindow::getResultMessage(ResultCode resultCode, QString* text) {
    switch (resultCode) {
        case ADD_FRIEND_ALLOW:
            *text = tr("IDS_ADD_FRIEND_ALLOW");
            break;
        case ADD_FRIEND_NOT_ALLOW:
            *text = tr("IDS_ADD_FRIEND_NOT_ALLOW");
            break;
        case ALREADY_BE_FRIENDS:
            *text = tr("IDS_ALREADY_BE_FRIENDS");
            break;
        case FRIEND_NAME_EQUAL_SELF_NAME:
            *text = tr("IDS_FRIEND_NAME_EQUAL_SELF_NAME");
            break;
        case NETWORK_ERROR:
            *text = tr("IDS_NETWORK_ERROR");
            break;
        case PASSWORD_WRONG:
            *text = tr("IDS_PASSWORD_WRONG");
            break;
        case REG_SUCCEEDED:
            *text = tr("IDS_REG_SUCCEEDED");
            break;
        case TOO_MANY_FRIENDS:
            *text = tr("IDS_TOO_MANY_FRIENDS");
            break;
        case USER_ALREADY_LOGON:
            *text = tr("IDS_USER_ALREADY_LOGON");
            break;
        case USER_EXISTS:
            *text = tr("IDS_USER_EXISTS");
            break;
        case USER_NOT_FOUND:
            *text = tr("IDS_USER_NOT_FOUND");
            break;
        default:
            break;
    }
}

/**
 * "添加好友"按钮的单击响应方法。
 */
void MainWindow::on_buttonAddFriend_triggered() {
    // 显示输入窗口，让用户输入好友名
    QInputDialog inputDialog(this);
    bool ok = false;
    QString username = inputDialog.getText(this, " ", tr("IDS_PLEASE_INPUT_USERNAME"), QLineEdit::Normal, "", &ok);
    if (!ok) {
        return;
    }

    // 执行添加好友
    ResultCode resultCode = mClient->addFriend(username.toStdString().c_str());
    if (resultCode != SUCCEEDED) {
        QString text;
        this->getResultMessage(resultCode, &text);
        QMessageBox::critical(this, " ", text);
    }
}

/**
 * "离线"按钮的单击响应方法。
 */
void MainWindow::on_buttonLogoff_triggered() {
    // 设置各种控件的状态
    this->changeState(false);

    // 清空各种列表
    ui->listViewUsers->clear();
    this->clearChatWindow();

    // 发送离线请求
    mClient->logoff();
}

/**
 * "登录"按钮的单击响应方法。
 */
void MainWindow::on_buttonLogon_triggered() {
    // 显示登录窗口
    LogonWindow logonWindow(this);
    int clickedButton = logonWindow.exec();
    if (clickedButton == LogonWindow::OK) {
        // 登录
        mClient->logon(logonWindow.getUsername(), logonWindow.getPassword());
    }
}

/**
 * "群发消息"按钮的单击响应方法。
 */
void MainWindow::on_buttonMChat_triggered() {
    this->getChatWindow(ImProtocol::MULTI_CHAT)->show();
}

/**
 * "注册"按钮的单击响应方法。
 */
void MainWindow::on_buttonReg_triggered() {
    // 显示注册窗口
    RegWindow regWindow(this);
    int clickedButton = regWindow.exec();
    if (clickedButton == QDialog::Accepted) {
        // 注册
        mClient->reg(regWindow.getUsername(), regWindow.getPassword(), regWindow.getIconIndex());
    }
}

/**
 * 双击好友列表控件的响应方法。
 * @param item  被双击的表项
 */
void MainWindow::on_userListView_itemDoubleClicked(QListWidgetItem *item) {
    const char* friendName = item->text().toStdString().c_str();
    this->getChatWindow(friendName)->show();
}

/**
 * 聊天事件的响应方法（客户端到服务器）。
 * @param chatInfo  聊天信息
 */
void MainWindow::onChatC2S(ChatInfo* chatInfo) {
    mClient->chat(chatInfo);
}

/**
 * 聊天事件的响应方法（服务器到客户端）。
 * @param chatInfo  聊天信息
 */
void MainWindow::onChatS2C(ChatInfo* chatInfo) {
    QString dstUsername(chatInfo->mDstUsername);
    ChatWindow* chatWindow = nullptr;
    if (dstUsername == ImProtocol::MULTI_CHAT) {
        chatWindow = this->getChatWindow(ImProtocol::MULTI_CHAT);
    } else {
        chatWindow = this->getChatWindow(chatInfo->mSrcUsername);
    }
    chatWindow->setContent(chatInfo);
    chatWindow->show();
}

/**
 * 好友离线事件的响应方法。
 * @param request   离线请求
 */
void MainWindow::onFriendLogoff(LogoffRequest* request) {
    ui->listViewUsers->changeItemColor(request->mUsername, false);
}

/**
 * 好友登录事件的响应方法。
 * @param friendLogon   好友登录信息
 */
void MainWindow::onFriendLogon(FriendLogon* friendLogon) {
    ui->listViewUsers->changeItemColor(friendLogon->mUsername, true);
}

/**
 * 得到添加好友请求事件的响应方法。
 * @param request   添加好友请求
 */
void MainWindow::onGetAddFriendRequest(AddFriendRequest* request) {
    QString message(request->mSrcUsername);
    message += tr("IDS_CONFIRM_ADD_FRIEND");
    int clickedButton = QMessageBox::question(this, " ", message);
    bool allow = clickedButton == QMessageBox::Yes;
    mClient->allowAddFriend(allow, request);
    if (allow) {
        this->addOneFriend(request->mSrcUsername, request->mIconIndex);
        mLabelFriendCount.setText(tr("IDS_FRIEND_COUNT").arg(mClient->getFriendCount()));
    }
}

/**
 * 得到添加好友结果事件的响应方法。
 * @param result    添加好友结果
 */
void MainWindow::onGetAddFriendResult(AddFriendResult* result) {
    QString message;
    this->getResultMessage(result->mResultCode, &message);
    QString dstUsername(result->mDstUsername);
    if (result->mResultCode == ADD_FRIEND_ALLOW) {
        message = message.arg(dstUsername);
        this->addOneFriend(result->mDstUsername, result->mDstIconIndex, true);
        mLabelFriendCount.setText(tr("IDS_FRIEND_COUNT").arg(mClient->getFriendCount()));
        QMessageBox::information(this, " ", message);
    } else if (result->mResultCode == ALREADY_BE_FRIENDS ||
        result->mResultCode == ADD_FRIEND_NOT_ALLOW ||
        result->mResultCode == USER_NOT_FOUND) {
        message = dstUsername + message;
        QMessageBox::warning(this, " ", message);
    }
}

/**
 * 登录事件的响应方法。
 * @param result    登录结果
 */
void MainWindow::onGetLogonResult(LogonResult* result) {
    if (result->mResultCode == LOGON_SUCCEEDED) {
        this->changeState(true);
        this->addAllFriends(result);
    } else {
        QString message;
        this->getResultMessage(result->mResultCode, &message);
        QMessageBox::critical(this, " ", message);
    }
}

/**
 * 注册事件的响应方法。
 * @param result    注册结果
 */
void MainWindow::onGetRegResult(RegResult* result) {
    QString message;
    this->getResultMessage(result->mResultCode, &message);
    if (result->mResultCode == REG_SUCCEEDED) {
        this->changeState(true);
        QMessageBox::information(this, " ", message);
    } else {
        QMessageBox::critical(this, " ", message);
    }
}
